﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using MediaCentral.Services.DAL.Entities;
using MediaCentral.Services.Global;
using Microsoft.SharePoint.Taxonomy;
using System.Globalization;

namespace MediaCentral.Services.DAL
{
    //TODO: Implement a real pattern here. Not just a static class.
    public class SharePoint
    {
        public static List<Video> GetVideosByTag(string listName, string tag, int limit)
        {
            SPList list = SPContext.Current.Web.Lists.TryGetList(listName);
            List<Video> videos = new List<Video>();

            if (list != null)
            {
                SPQuery query = new SPQuery();
                if (!string.IsNullOrEmpty(tag))
                    query.Query = GetTaxonomyFieldCamlQuery(tag, SPContext.Current.Site);

                if (limit == Int32.MinValue)
                    limit = 20;

                query.RowLimit = Convert.ToUInt32(limit);
                query.Query += "<OrderBy><FieldRef Name='Created' Ascending='False' /></OrderBy>";

                if (listName == "YouTubeVideos")
                    videos.AddRange(ConvertYouTubeListItemsToVideos(list.GetItems(query)));
                else
                    videos.AddRange(ConvertLocalListItemsToVideos(list.GetItems(query)));
            }

            return videos;
        }

        public static List<Video> SearchVideos(string listName, string query)
        {
            List<Video> videos = new List<Video>();
            SPList list = SPContext.Current.Web.Lists.TryGetList(listName);

            if (list != null)
            {
                SPQuery camlQuery = new SPQuery();
                if (!string.IsNullOrEmpty(query))
                    camlQuery.Query = GetSearchCamlQuery(query, SPContext.Current.Site);
                camlQuery.RowLimit = 20;

                if (listName == "YouTubeVideos")
                    videos.AddRange(ConvertYouTubeListItemsToVideos(list.GetItems(camlQuery)));
                else
                    videos.AddRange(ConvertLocalListItemsToVideos(list.GetItems(camlQuery)));
            }

            return videos;
        }

        public static bool UpdateVideo(string libName, int id, string title, string description, string thumbnail, string tags)
        {
            SPWeb web = SPContext.Current.Web;
            SPList lib = web.Lists.TryGetList(libName);

            if (string.IsNullOrEmpty(thumbnail.Trim()))
                thumbnail = "/MediaCentral/DefaultVideoThumbnail.jpg";

            if (lib != null)
            {
                SPListItem item = lib.GetItemById(id);
                item["Title"] = title;
                if (libName == "LocalVideos")
                {
                    item["_Comments"] = description;
                    item["AlternateThumbnailUrl"] = thumbnail;
                }
                else
                {
                    item["Description"] = description;
                    item["Thumbnail"] = thumbnail;
                }

                item.Web.AllowUnsafeUpdates = true;
                UpdateItemTerms(ref item, tags);

                item.Update();

                item.Web.AllowUnsafeUpdates = false;
            }

            return true;
        }

        public static bool AddNewVideo(string listName, string title, string description, string thumbnail, string videoid, string tags)
        {
            SPList list = SPContext.Current.Web.Lists[listName];
            if (list != null)
            {
                if (string.IsNullOrEmpty(thumbnail.Trim()))
                    thumbnail = "/MediaCentral/DefaultVideoThumbnail.jpg";

                int maxLength = (description.Length < 255) ? description.Length : 250;

                SPListItem newItem = list.Items.Add();
                newItem["Title"] = title;

                if (listName == "LocalVideos")
                {
                    newItem["_Comments"] = description.Substring(0, 230);
                    newItem["AlternateThumbnailUrl"] = thumbnail;
                }
                else
                {
                    newItem["Description"] = description.Substring(0, maxLength);
                    newItem["Thumbnail"] = thumbnail;
                    newItem["VideoID"] = videoid;
                }

                newItem.Web.AllowUnsafeUpdates = true;
                UpdateItemTerms(ref newItem, tags);
                newItem.Update();
                newItem.Web.AllowUnsafeUpdates = false;

                return true;
            }
            return false;
        }

        public static string[] GetAllTags()
        {
            List<string> tags = new List<string>();

            TaxonomySession taxSession = new TaxonomySession(SPContext.Current.Site);
            TermStore termStore = taxSession.TermStores["Managed Metadata Service"];
            Group group = termStore.Groups["MediaCentral"];
            TermSet termSet = group.TermSets["VideoTags"];

            foreach (Term term in termSet.Terms)
            {
                tags.Add(term.Name);
            }

            return tags.ToArray();
        }

        private static Video LocalVideoSPItemToVideo(SPListItem item)
        {
            string thumbnailUrl = (String)item["AlternateThumbnailUrl"] ?? string.Empty;
            SPFieldUrlValue urlValue = new SPFieldUrlValue(thumbnailUrl);
            thumbnailUrl = urlValue.Url;

            Video vid = new Video();
            vid.ID = item.ID;
            vid.Title = item.File.Title;
            vid.Description = item["_Comments"].ToString();
            vid.IsLocalVid = true;
            vid.Thumbnail = thumbnailUrl;
            vid.VideoUrl = item.File.ServerRelativeUrl;
            vid.Tags = GetTagsAsString(item["Tags"] as TaxonomyFieldValueCollection);

            return vid;
        }
        private static List<Video> ConvertLocalListItemsToVideos(SPListItemCollection items)
        {
            List<Video> videos = new List<Video>();
            foreach (SPListItem item in items)
            {
                videos.Add(LocalVideoSPItemToVideo(item));
            }
            return videos;
        }

        private static Video YouTubeSPItemToVideo(SPListItem item)
        {
            string thumbnailUrl = (String)item["Thumbnail"] ?? string.Empty;

            Video vid = new Video();
            vid.ID = item.ID;
            vid.Title = item.Title;
            vid.Description = (string)item["Description"] ?? string.Empty;
            vid.IsLocalVid = false;
            vid.Thumbnail = thumbnailUrl;
            vid.VideoUrl = Constants.YouTubeEmbedUrl + item["VideoID"];
            vid.Tags = GetTagsAsString(item["Tags"] as TaxonomyFieldValueCollection);

            return vid;
        }
        private static List<Video> ConvertYouTubeListItemsToVideos(SPListItemCollection items)
        {
            List<Video> videos = new List<Video>();
            foreach (SPListItem item in items)
            {
                videos.Add(YouTubeSPItemToVideo(item));
            }
            return videos;
        }

        private static string GetTagsAsString(TaxonomyFieldValueCollection fieldValues)
        {
            StringBuilder returnString = new StringBuilder();
            foreach (var fieldValue in fieldValues)
            {
                returnString.AppendFormat("{0},", fieldValue.Label);
            }

            return returnString.ToString().TrimEnd(',');
        }

        private static void UpdateItemTerms(ref SPListItem item, string terms)
        {
            TaxonomySession taxSession = new TaxonomySession(item.Web.Site);
            TermStore termStore = taxSession.TermStores["Managed Metadata Service"];
            Group group = termStore.Groups["MediaCentral"];
            TermSet termSet = group.TermSets["VideoTags"];

            List<Term> tags = new List<Term>();

            string[] termsList = terms.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

            foreach (string term in termsList)
            {
                Term tagTerm;
                //if (!termSet.Terms.Any(t => t.Name == TaxonomyItem.NormalizeName(term)))
                //if (termSet.Terms[term.Trim()] == null)
                try
                {
                    tagTerm = termSet.Terms[TaxonomyItem.NormalizeName(term).Trim()];
                }
                catch (Exception)
                {
                    // 2057 breaks it, says 'outside valid range of values'. Dafuq?
                    // tagTerm = termSet.CreateTerm(TaxonomyItem.NormalizeName(term).Trim(), CultureInfo.CurrentCulture.LCID);
                    tagTerm = termSet.CreateTerm(TaxonomyItem.NormalizeName(term).Trim(), 1033);
                    termStore.CommitAll();
                }
 
                tags.Add(tagTerm);
            }

            TaxonomyField tagfield = item.Fields["Tags"] as TaxonomyField;

            tagfield.SetFieldValue(item, tags);
        }

        private static int[] GetTermIds(string term, SPSite site)
        {
            TaxonomySession taxSession = new TaxonomySession(site);
            TermStore termStore = taxSession.TermStores["Managed Metadata Service"];
            Group group = termStore.Groups["MediaCentral"];
            TermSet termSet = group.TermSets["VideoTags"];

            return TaxonomyField.GetWssIdsOfTerm(site, termStore.Id, termSet.Id, termSet.Terms[term].Id, true, 500);
        }

        private static string GetTaxonomyFieldCamlQuery(string term, SPSite site)
        {
            try
            {
                StringBuilder camlQuery = new StringBuilder();
                SPSecurity.RunWithElevatedPrivileges(delegate
                {
                    int[] ids = GetTermIds(term, new SPSite(site.ID));

                    string camlFormatString = "<Value Type='Integer'>{0}</Value>";
                    

                    camlQuery.Append("<Where><In><FieldRef LookupId='TRUE' Name='Tags' /><Values>");
                    foreach (int id in ids)
                    {
                        camlQuery.AppendFormat(camlFormatString, id);
                    }

                    camlQuery.Append("</Values></In></Where>");
                });
                return camlQuery.ToString();
            }
            catch (Exception e)
            {
                return string.Empty;
            }
            
        }

        private static string GetSearchCamlQuery(string query, SPSite site)
        {
            bool hasTerms = true;
            int[] ids = null;
            try
            {
                ids = GetTermIds(query, site);
            }
            catch (Exception)
            {
                // Search query doesn't have any direct tags
                hasTerms = false;
            }
            string camlFormatString = "<Value Type='Integer'>{0}</Value>";
            StringBuilder camlQuery = new StringBuilder();

            camlQuery.Append("<Where>");

            if (hasTerms)
            {
                camlQuery.Append("<Or><In><FieldRef LookupId='TRUE' Name='Tags' /><Values>");

                foreach (int id in ids)
                {
                    camlQuery.AppendFormat(camlFormatString, id);
                }

                camlQuery.Append("</Values></In>");
            }

            camlQuery.AppendFormat("<Contains><FieldRef Name='Title' /><Value Type='Text'>{0}</Value></Contains>", query);

            if (hasTerms)
                camlQuery.Append("</Or>");

            camlQuery.Append("</Where>");

            //camlQuery.Append("<OrderBy><FieldRef Name='Created' Ascending='False' /></OrderBy>");

            return camlQuery.ToString();
        }
    }
}
